home *** CD-ROM | disk | FTP | other *** search
- // msounit.cpp: Menu screen object (mso) class implementation
-
- #include "stdio.h"
- #include "process.h"
- #include "stdlib.h"
- #include "string.h"
- #include "msounit.h"
-
- // -------------------- Meso Methods -----------------------
- Meso::Meso(char *N, ActionProc A)
- // Initializes a menu entry object by assigning it a name and
- // action. The object will have no border and will have
- // default colors.
- // CORRECTION: pg 256, DefColors passed by reference,
- // not by pointer as in book
- : Wso(0x00, 0x00, DefColors)
- {
- strncpy(Name, N, 39); Name[39] = 0; // Ensure null termination
- Action = A;
- SetSize(Panel->TextWidth(N), Panel->TextHeight(1));
- }
-
- void Meso::Draw(void)
- // Displays a menu entry
- {
- Wso::Draw(); // Draw the window object
- Panel->HzWrt(0, 0, Name, Panel->Colors.Wc);
- }
-
- void Meso::Prompt(void)
- // Prompts a menu entry by highlighting it
- {
- Wso::Prompt(); // Select the window
- Panel->Fill(0, 0, Panel->Interior->Wd, Panel->TextHeight(1),
- ' ', Panel->Colors.Fc);
- Panel->HzWrt(0, 0, Name, Panel->Colors.Fc);
- }
-
- void Meso::UnPrompt(void)
- // Unprompts the menu entry by re-displaying it
- // with its standard attribute
- {
- Panel->Fill(0, 0, Panel->Interior->Wd, Panel->TextHeight(1),
- ' ', Panel->Colors.Wc);
- Panel->HzWrt(0, 0, Name, Panel->Colors.Wc);
- Wso::UnPrompt(); // De-select window
- }
-
- void Meso::OnKeyStroke(MsgPkt &M)
- // Processes an input key. The Enter key selects the entry. If
- // any other key is pressed the entry's Base (which is the
- // menu itself) handles it
- {
- if (M.Code == CrKey)
- Activate(M);
- else Base->OnKeyStroke(M); // Send key to base
- }
-
- void Meso::OnClose(MsgPkt &M)
- // Closing a menu entry means to close the menu as well
- {
- Base->SwitchFocus(M);
- M.RtnCode = Close; // Effectively tells the base to close
- }
-
- void Meso::Activate(MsgPkt &M)
- // Call the menu entry's action. Otherwise, leave the menu
- // entry. (Thus, if a MouseUp event occurs outside the menu,
- // the entry is de-selected.)
- {
- if (Active) { // The entry must be selected
- Wso::Activate(M);
- Action(this, M); // Execute the assigned action
- }
- else {
- Leave(M); // Leave the menu entry
- }
- }
-
- // ----------------------- Meso List Methods ----------------------
- MesoList::MesoList(void)
- // Initializes the list of menu entry objects. The list is
- // implemented as a circular list.
- {
- Last = NULL; // Indicates the list is empty
- }
-
- MesoList::~MesoList(void)
- // This method does nothing because the entries on the list
- // also appear on the Iso stack, and will be destroyed when
- // the stack is destroyed.
- {
- return;
- }
-
- void MesoList::Append(Meso *Me)
- // Appends a menu entry to the menu list
- {
- if (Last != NULL) { // List has entries
- Me->Next = Last->Next;
- Last->Next = Me; // Add new element
- Last = Last->Next; // Update end of list pointer
- }
- else { // List is empty
- Last = Me; // Place at top of list
- Last->Next = Me;
- }
- }
-
- // ------------ Menu Screen Object Methods -------------
- Mso::Mso(MesoList *El, int Nc, int Nr, int Sp, int W, int H,
- int Bd, int Fa, ColorPak &Cp)
- // Initializes the menu object by creating a window
- // and setting up the menu entries
- : Wso(Bd, Fa, Cp) // Initialize the menu's window
- {
- Entries = El;
- CurrSeln = Entries->Last->Next;
- EntriesDrawn = 0;
- Spacing = Sp;
- SetupDim(Nc, Nr, W, H); // Sets up the menu dimensions
- Ncols = Nc; Nrows = Nr; // Store number of columns, rows
- SetSize(W, H); // Sets the menu width and height
- SetupEntries(); // Sets the size and attribute for each entry
- }
-
- void Mso::SetupDim(int &Nc, int &Nr, int &W, int &H)
- // Sets up the menu's dimensions
- {
- int SumLen, NumEntries, MaxEntryLen, TxtLen;
- Meso *P;
-
- NumEntries = 0; MaxEntryLen = 0; SumLen = 0;
- P = Entries->Last->Next;
- if (Nr == 1) { // Horizontal menu
- do {
- // We use Absc below so coords will not be translated just yet
- P->SetLocn(SumLen, 0, Absc);
- SumLen += Panel->TextWidth(P->Name) + Spacing;
- NumEntries++;
- P = P->Next;
- } while (P != Entries->Last->Next);
- SumLen -= Spacing;
- if (SumLen > W) W = SumLen;
- H = Panel->TextHeight(1);
- Nc = NumEntries;
- Nr = 1;
- }
- else if (Nc == 1) { // Vertical menu
- do {
- // We use Absc below so coords will not be translated just yet
- P->SetLocn(0, Panel->TextHeight(NumEntries), Absc);
- TxtLen = Panel->TextWidth(P->Name);
- if (TxtLen > MaxEntryLen) MaxEntryLen = TxtLen;
- NumEntries++;
- P = P->Next;
- } while (P != Entries->Last->Next);
- if (MaxEntryLen > W) W = MaxEntryLen;
- H = Panel->TextHeight(NumEntries);
- Nr = NumEntries; Nc = 1;
- }
- else { // Rectangular menu:
- printf("Rectangular menus not supported\n");
- exit(1);
- }
- }
-
- int Mso::EntryWidth(Meso *Me)
- // Calculates the width of a menu entry
- {
- if (IsHz())
- return Panel->TextWidth(Me->Name);
- else return Panel->Interior->Wd;
- }
-
- void Mso::SetupEntries(void)
- // Sizes the menu entries and initializes their colors
- {
- Meso *P;
- P = Entries->Last->Next; // Get the first menu entry
- do {
- P->Panel->SetSize(EntryWidth(P), Panel->TextHeight(1));
- P->Panel->Colors = Panel->Colors;
- P = P->Next;
- } while (P != Entries->Last->Next);
- }
-
- void Mso::Open(Iso *B, int X, int Y)
- // Open up the menu, open up the menu entries too
- {
- Meso *P;
-
- Wso::Open(B, X, Y);
- P = Entries->Last->Next; // Get the first menu entry
- do {
- // Display the menu item
- P->Open(this, P->Panel->Overall->Xul, P->Panel->Overall->Yul);
- P = P->Next; // Get the next menu entry
- } while(P != Entries->Last->Next);
- EntriesDrawn = True; // Indicates menu entries are displayed
- }
-
-
- void Mso::MoveLoop(MsgPkt &M)
- // Calls the MoveLoop from the parent class to move the menu.
- // This feature supports tear-away menus. We return a MouseUp
- // event to cause the current menu entry to be selected.
- {
- Wso::MoveLoop(M);
- M.RtnCode = MouseUp;
- }
-
- void Mso::Activate(MsgPkt &M)
- // This method handles the case when a MouseUp occurs on
- // the menu's border (see MoveLoop). We wish to switch focus
- // to the current menu entry so that it is highlighted.
- {
- CurrSeln = (Meso *)(SubMgr->Top);
- CurrSeln->SwitchFocus(M);
- }
-
- void Mso::Leave(MsgPkt &M)
- // Leaves a menu. Before leaving, we must record the
- // current menu entry selection.
- {
- CurrSeln = (Meso *)(SubMgr->Top); // Save current entry
- Wso::Leave(M); // Leave the menu
- }
-
- void Mso::OnKeyStroke(MsgPkt &M)
- // Trap and process the arrow keys, otherwise pass the
- // key press event to the inherited method.
- {
- switch(M.Code) { // Check for arrow keys
- case UpKey : if (IsVt()) Back(M); break; // To previous entry
- case DownKey : if (IsVt()) Forw(M); break; // To next entry
- case LeftKey : if (IsHz()) Back(M); break;
- case RightKey : if (IsHz()) Forw(M); break;
- default:
- Wso::OnKeyStroke(M); // Send other keys to base class
- }
- }
-
- void Mso::Forw(MsgPkt &M)
- // Advances to the next menu entry in the menu object
- {
- CurrSeln = (Meso *)(SubMgr->Top); // Find current selection
- CurrSeln->Next->SwitchFocus(M); // Go to next entry
- }
-
- void Mso::Back(MsgPkt &M)
- // Backs up to the previous menu entry
- {
- Meso *P;
- CurrSeln = (Meso *)(SubMgr->Top); // Find current selection
- P = CurrSeln;
- while (P->Next != CurrSeln) P = P->Next;
- CurrSeln = P; // Go to previous entry
- CurrSeln->SwitchFocus(M); // Select the new entry
- }
-
-
- // ----------- Pull-down menu bar methods ---------------
- PullDnBar::PullDnBar(MesoList *Items, int W, int Sp, ColorPak &Cp)
- // Initializea a pull-down menu bar object
- : Mso(Items, 0, 1, Sp, W,
- Items->Last->Next->Panel->Overall->Ht, 0x00, 0x00, Cp)
- {
- SubMso = NULL;
- }
-
- void PullDnBar::OnKeyStroke(MsgPkt &M)
- // First, let the inherited Mso::OnKeyStroke handle the
- // keystroke. If the keystroke is a left or right arrow key,
- // a new entry will be selected by Mso::OnKeyStroke, so
- // activate the new menu entry, causing the drop menu to
- // drop down.
- {
- Mso::OnKeyStroke(M);
- if ((M.Code == LeftKey) || (M.Code == RightKey))
- M.Focus->Activate(M);
- }
-
- // -------------------- Pull Down Menu ------------------------
-
- Pmso::Pmso(MesoList *Items, int W, int H, int Sp,
- int Ba, int Fa, ColorPak &Cp)
- // Initializes the main pull-down menu screen object
- : Wso(Ba, Fa, Cp)
- {
- Bar = new PullDnBar(Items, W, Sp, Cp);
- SetSize(Bar->Panel->Frame->Wd, H);
- Inner = new Wso(0x00, 0x00, Cp);
- Inner->SetSize(Panel->Interior->Wd,
- Panel->Interior->Ht -
- Panel->TextHeight(1));
- }
-
- void Pmso::Open(Iso *B, int X, int Y)
- // Displays the pull-down menu system by opening the main
- // pull-down object on an Iso
- {
- Wso::Open(B, X, Y);
- Bar->Open(this, 0, 0);
- Inner->Open(this, 0, Panel->TextHeight(1));
- }
-
- // ------------------------------------------------------------------
- Dmso::Dmso(MesoList *Items, int W, int Ba, int Fa, ColorPak &Cp)
- // Initializes a drop menu screen object
- : Mso(Items, 1, 0, 2, W, 0, Ba, Fa, Cp)
- {
- Parent = NULL;
- }
-
- void Dmso::OnClose(MsgPkt &M)
- // Closes a drop menu screen object. Note how we must
- // set the PullDnBar's SubMso field to NULL, and how we
- // must do a typecast.
- {
- ((PullDnBar *)(Parent->Base))->SubMso = NULL;
- Mso::OnClose(M);
- }
-
- void Dmso::OnKeyStroke(MsgPkt &M)
- // Sends all LeftKey and RightKey events to the pulldown
- // menu, else, let the inherited method (Mso::OnKeyStroke)
- // handle the event.
- {
- if (M.Code == LeftKey || M.Code == RightKey) {
- Parent->Base->OnKeyStroke(M);
- }
- else {
- Mso::OnKeyStroke(M);
- }
- }
-
- // -------------------------------------------------------------
-
- void PmesoAction(Wso *Src, MsgPkt &M)
- // The action for a pulldown menu entry screen object is
- // to switch focus to the last menu entry selected in the
- // drop menu.
- {
- ((Pmeso *)(Src))->Vm->CurrSeln->SwitchFocus(M);
- }
-
- Pmeso::Pmeso(char *N, Dmso *D)
- // Initializes a pull-down menu entry screen object
- : Meso(N, PmesoAction)
- {
- Vm = D;
- }
-
- void Pmeso::OnKeyStroke(MsgPkt &M)
- // Traps DownKey events so that they cause the sub-menu to drop
- {
- if (M.Code == DownKey)
- Activate(M); else Meso::OnKeyStroke(M);
- }
-
- void Pmeso::SwitchFocus(MsgPkt &M)
- // Switches focus to Self, erases any drop menu
- // currently displayed, and draws Self's drop menu
- {
- int Xcoord;
- if (!Active) {
- Meso::SwitchFocus(M); // Must do this first
- if (((PullDnBar *)(Base))->SubMso != NULL) {
- ((PullDnBar *)(Base))->SubMso->Leave(M);
- ((PullDnBar *)(Base))->SubMso->OnClose(M);
- ((PullDnBar *)(Base))->SubMso = NULL;
- }
- if (Vm != NULL) { // If there is a drop menu
- Xcoord = Panel->Overall->Xul - Base->Panel->Overall->Xul;
- if (!Vm->EntriesDrawn) {
- Vm->Open(((Pmso *)(Base->Base))->Inner, Xcoord, 0);
- }
- else Vm->Reopen(Xcoord, 0);
- ((PullDnBar *)Base)->SubMso = Vm;
- Vm->Parent = this;
- }
- }
- }
-
-
-